package com.iphanta.community.activity.photographic.common;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 墨声 E-mail: zehong.hongframe.huang@gmail.com
 * create time: 4/12/22 10:12 AM
 */
public class BallBoxSelector {

    private Random random;

    private int totalWeight = 0;
    private boolean sameWeight = true;
    private List<BallBox> collection;

    public BallBoxSelector(List<BallBox> collection, Random random) {
        this.collection = collection;
        this.random = random;

        for (int i = 0; i < collection.size(); i++) {
            int weight = getWeight(collection.get(i));
            this.totalWeight += weight;
            if (this.sameWeight && i > 0
                    && weight != getWeight(this.collection.get(i - 1))) {
                this.sameWeight = false;
            }
        }
    }

    public List<Long> choice(Integer n) {
        return dynamicIds(choice0(n));
    }

    protected List<BallBox> choice0(Integer n) {
        if (n >= this.collection.size()) {
            return this.collection;
        }
        List<BallBox> result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            result.add(select());
        }
        return result;
    }

    private BallBox select() {

        int length = this.collection.size();

        if (this.totalWeight > 0 && !this.sameWeight) {
            int offset = this.random.nextInt(this.totalWeight);

            for (int i = 0; i < length; i++) {
                offset -= getWeight(collection.get(i));
                if (offset < 0) {
                    BallBox box = collection.remove(i);
                    this.totalWeight = this.totalWeight - getWeight(box);
                    return box;
                }
            }
        }
        return collection.get(this.random.nextInt(length));
    }

    private List<Long> dynamicIds(List<BallBox> collection) {
        return collection.stream().map(e -> e.getDynamicId())
                .collect(Collectors.toList());
    }

    private int getWeight(BallBox ballBox) {
        return ballBox.getTotal() - ballBox.getExposure();
    }


}
